from collections import OrderedDict

class LruDict:
    def __init__(self, capacity, eviction_policy=None):
        self.capacity = capacity
        self.cache = OrderedDict()
        self.eviction_policy = eviction_policy if eviction_policy else self.default_eviction_policy

    def get(self, key):
        if key not in self.cache:
            return None
        else:
            # Move the accessed item to the end to mark it as recently used
            self.cache.move_to_end(key)
            return self.cache[key]

    def put(self, key, value):
        if key in self.cache:
            # Update the value and move it to the end to mark it as recently used
            self.cache.move_to_end(key)
        self.cache[key] = value
        if len(self.cache) > self.capacity:
            # Evict the least recently used item
            self.evict()

    def evict(self):
        if self.eviction_policy:
            self.eviction_policy(self.cache)

    def default_eviction_policy(self, cache):
        # Remove the first item (least recently used)
        cache.popitem(last=False)

    def set_eviction_policy(self, eviction_policy):
        self.eviction_policy = eviction_policy

# Example usage:
if __name__ == "__main__":
    # Create an LruDict with a capacity of 3
    lru_dict = LruDict(capacity=3)

    # Add some items
    lru_dict.put("a", 1)
    lru_dict.put("b", 2)
    lru_dict.put("c", 3)

    # Access an item to mark it as recently used
    print(lru_dict.get("a"))  # Output: 1

    # Add another item, which will trigger an eviction
    lru_dict.put("d", 4)

    # Check the contents of the LruDict
    print(lru_dict.cache)  # Output: OrderedDict([('a', 1), ('c', 3), ('d', 4)])

    # Custom eviction policy example
    def custom_eviction_policy(cache):
        # Evict the item with the smallest value
        min_key = min(cache.keys(), key=lambda k: cache[k])
        cache.pop(min_key)

    lru_dict.set_eviction_policy(custom_eviction_policy)

    # Add another item, which will trigger the custom eviction policy
    lru_dict.put("e", 5)

    # Check the contents of the LruDict
    print(lru_dict.cache)  # Output: OrderedDict([('a', 1), ('d', 4), ('e', 5)])